/*
 * Copyright 2006-2008 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.martinimix.dao.syndication;

import java.util.Collection;
import java.util.List;

import net.martinimix.beans.bind.BindingService;
import net.martinimix.beans.bind.BindingServiceAware;
import net.martinimix.dao.BusinessObjectTemplate;
import net.martinimix.dao.DataAccessException;
import net.martinimix.dao.SimpleBusinessObjectTemplate;
import net.martinimix.domain.syndication.SyndicationFeed;
import net.martinimix.domain.syndication.SyndicationFeedEntry;

import com.bluemartini.database.BMDatabaseManager;
import com.bluemartini.database.BindArray;
import com.bluemartini.database.DBUtil;
import com.bluemartini.dna.BMException;
import com.bluemartini.dna.BusinessObject;
import com.bluemartini.dna.BusinessObjectArray;

/**
 * Provides a Blue Martini business object based syndication feed data access object.
 * 
 * @author Scott Rossillo
 *
 */
public class BlueMartiniSyndicationFeedDao implements SyndicationFeedDao, BindingServiceAware {

	protected final static String DATABASE = "martinimix";
	
	private BindingService bindingService;
	
	/**
	 * Creates a new Blue Martini business object based syndication feed data access object.
	 */
	public BlueMartiniSyndicationFeedDao() { }
	
	/* (non-Javadoc)
	 * @see net.martinimix.dao.syndication.SyndicationFeedDao#findFeed(long)
	 */
	public SyndicationFeed findFeed(long id) {
		
		SyndicationFeed feed;
		BusinessObject boSyndFeed;
		BindArray ba = new BindArray();
		
		ba.addLong(id);
		
		BMDatabaseManager.pushCurrentDatabase(DATABASE);
		try {
			boSyndFeed = DBUtil.selectBusinessObject("SYND_FEED", "SYF_Id = ?", ba);
		} catch (BMException e) {
			throw new DataAccessException("Unable to load feeds: " + e.getMessage(), e);
		} finally {
			BMDatabaseManager.popCurrentDatabaseQuiet(DATABASE);
		}
		
		feed = (SyndicationFeed) bindingService.bindBean(boSyndFeed, new SyndicationFeed());
		feed.setEntries(findFeedEntries(feed.getId().longValue()));
		
		return feed;
	}
	
	/**
	 * Returns a list of feed entries for the given feed identifier.
	 * 
	 * @param feedId
	 * @return
	 */
	protected List findFeedEntries(long feedId) {
		
		BusinessObjectArray boEntryArray;
		BindArray ba = new BindArray();
		
		ba.addLong(feedId);
		
		BMDatabaseManager.pushCurrentDatabase(DATABASE);
		try {
			boEntryArray = DBUtil.selectBusinessObjectArray("SYND_FEED_ENTRY", "SFE_SYF_Id = ?", ba, 0, -1);
		} catch (BMException e) {
			throw new DataAccessException("Unable to load feeds: " + e.getMessage(), e);
		} finally {
			BMDatabaseManager.popCurrentDatabaseQuiet(DATABASE);
		}
		
		return bindingService.bindBeans(boEntryArray, new SyndicationFeedEntry());
	}

	/* (non-Javadoc)
	 * @see net.martinimix.dao.syndication.SyndicationFeedDao#getAllFeeds()
	 */
	public Collection getAllFeeds() {

		BusinessObjectArray boSyndFeedArray;
		
		BMDatabaseManager.pushCurrentDatabase(DATABASE);
		try {
			boSyndFeedArray = DBUtil.selectBusinessObjectArray("SYND_FEED", "1=1", 0, -1);
		} catch (BMException e) {
			throw new DataAccessException("Unable to load feeds: " + e.getMessage(), e);
		} finally {
			BMDatabaseManager.popCurrentDatabaseQuiet(DATABASE);
		}
		
		return bindingService.bindBeans(boSyndFeedArray, new SyndicationFeed());
	}

	/* (non-Javadoc)
	 * @see net.martinimix.dao.syndication.SyndicationFeedDao#save(com.sun.syndication.feed.synd.SyndFeed)
	 */
	public void save(SyndicationFeed feed) {
		
		BusinessObjectTemplate tmpl = new SimpleBusinessObjectTemplate(bindingService, DATABASE);
		SyndicationFeed savedFeed;
		
		List entries = feed.getEntries();
		SyndicationFeedEntry entry;
		
		BMDatabaseManager.pushCurrentDatabase(DATABASE);
		try {
			BMDatabaseManager.beginDBTransaction();
			
			savedFeed = (SyndicationFeed) tmpl.save(feed, "SYND_FEED", feed.getId() == null);

			try {
				for(int i = 0; entries != null && i < entries.size(); i++) {	
					entry = (SyndicationFeedEntry) entries.get(i);
					entry.setSyndicationFeedId(savedFeed.getId());
					save(entry);
				}
				BMDatabaseManager.commitDBTransaction();
			} catch(DataAccessException e) {
				BMDatabaseManager.rollbackDBTransaction();
				throw e;
			}
		} catch (BMException e) {
			throw new DataAccessException("Unable to execute syndication feed saving transaction!" + e.getMessage(), e);
		} finally {
			BMDatabaseManager.popCurrentDatabaseQuiet(DATABASE);
		}
		
		feed.setId(savedFeed.getId());
		feed.setCreatedBy(savedFeed.getCreatedBy());
		feed.setCreateDate(savedFeed.getCreateDate());
		feed.setModifiedBy(savedFeed.getModifiedBy());
		feed.setModifyDate(savedFeed.getModifyDate());
	}
	
	/**
	 * Saves the given syndication feed entry.
	 * 
	 * @param entry the <code>SyndicationFeedEntry</code> to be saved
	 */
	protected void save(SyndicationFeedEntry entry) {
		
		if(entry.getSyndicationFeedId() == null) {
			throw new IllegalArgumentException("[SyndicationFeedEntry] feed id nust be set!");
		}
		
		BusinessObjectTemplate tmpl = new SimpleBusinessObjectTemplate(bindingService, DATABASE);
		SyndicationFeedEntry savedEntry;
		
		savedEntry = (SyndicationFeedEntry) tmpl.save(entry, "SYND_FEED_ENTRY", entry.getId() == null);
		
		entry.setId(savedEntry.getId());
		entry.setCreatedBy(savedEntry.getCreatedBy());
		entry.setCreateDate(savedEntry.getCreateDate());
		entry.setModifiedBy(savedEntry.getModifiedBy());
		entry.setModifyDate(savedEntry.getModifyDate());
		
	}

	/* (non-Javadoc)
	 * @see net.martinimix.dao.bind.BindingServiceAware#setBindingService(net.martinimix.dao.bind.BindingService)
	 */
	public void setBindingService(BindingService bindingService) {
		
		this.bindingService = bindingService;
	}

}
